package com.groupbuying.sysconfig.service.impl.notify;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayOpenPublicMessageSingleSendRequest;
import com.alipay.api.response.AlipayOpenPublicMessageSingleSendResponse;
import com.groupbuying.sysconfig.constants.WechatUrlConstants;
import com.groupbuying.sysconfig.domain.SysconfigPlatformInfoDO;
import com.groupbuying.sysconfig.dto.app.*;
import com.groupbuying.sysconfig.dto.mini.*;
import com.groupbuying.sysconfig.intercepter.ConfigContextHandler;
import com.groupbuying.sysconfig.service.notify.NotifyTemplate;

import com.groupbuying.sysconfig.service.wechat.WechatService;
import com.groupbuying.sysconfig.utils.ListsUtil;
import com.groupbuying.sysconfig.utils.OkHttpUtils;
import com.groupbuying.sysconfig.utils.apiresult.ApiResult;
import com.groupbuying.sysconfig.utils.apiresult.ApiResultCode;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.lang.reflect.Array;
import java.util.*;

/**
 * @Description 微信、支付宝消息体
 * @Author Davidbieber
 * @Email davidbieber@163.com
 * @Date 2019/10/17 11:52 AM
 * 单线程调用--静态常量处理
 */
@Service
public class NotifyTemplateImpl implements NotifyTemplate {

    protected static final Logger LOG = LoggerFactory.getLogger(NotifyTemplateImpl.class);

    @Autowired
    private WechatService wechatService;

    /**
     * TODO 数据传输有固定格式
     * 微信公众号消息模版
     * 微信公众号多个openID群推送
     *
     * @param params
     * @return
     */
    @Override
    public ApiResult doWechatAppTemplateNotify(Map<String, Object> params) {
        LOG.info("接收公众号消息发送的参数:{}", params);
        String openIdList = params.get("openId") == null ? null : params.get("openId").toString();
        //获取openId list
        LOG.info("openIds：{}", openIdList);
        String[] openIdArray = openIdList.substring(1, openIdList.length() - 1).split(",");
        List<String> openIds = Arrays.asList(openIdArray);
        String templateId = params.get("templateId") == null ? null : params.get("templateId").toString();
        LOG.info("获取前端参数:用户openId:{},模版ID:{}", openIds, templateId);
        String accessToken = wechatService.getAccessToken();
        LOG.info("获取accessToken:{}", accessToken);
        if (openIds.size() < 1 || openIds == null) {
            LOG.info("微信公众号用户openID列表为空");
            return ApiResult.failure("用户openID列表为空");
        }
        if (StringUtils.isEmpty(templateId)) {
            LOG.info("微信公众号模版templateId为空");
            return ApiResult.failure("用户模版ID为空");
        }
        if (StringUtils.isEmpty(accessToken)) {
            LOG.info("微信公众号accessToken为空");
            return ApiResult.failure("公众号accessToken为空");
        }
        //获取 keywords包体
        Map<String, String> dataMap = JSON.parseObject(params.get("data").toString(), Map.class);
        if (dataMap == null || dataMap.size() < 1) {
            LOG.info("消息体数据为空");
            return ApiResult.failure("公众号消息体为空");
        }
        List<AppDataInfo> appDataInfos = new ArrayList<>();
        for (String key : dataMap.keySet()) {
            AppDataInfo keyword = new AppDataInfo(key, dataMap.get(key).toString(), "#173177");
            appDataInfos.add(keyword);
        }
        //获取系统参数
        SysconfigPlatformInfoDO sysconfigPlatformInfoDO = ConfigContextHandler.getSysconfigInfo();
        MiniProgramInfo miniProgramInfo = new MiniProgramInfo(sysconfigPlatformInfoDO.getAppId(), sysconfigPlatformInfoDO.getPagePath());
        AppWechatInfo appWechatInfo = AppWechatInfo.builder()
                //用户openID
                .toUser(null)
                //模版ID
                .templateId(templateId)
                //公众号跳转路径
                .url(" ")
                //公众号跳转小程序
                .miniDataInfo(miniProgramInfo)
                //公众号消息体参数信息--待确认填充
                .data(appDataInfos)
                .build();
        Iterator<String> openIdIterator = openIds.iterator();
        while (openIdIterator.hasNext()) {
            String openId = openIdIterator.next();
            appWechatInfo.setToUser(openId);
            LOG.info("微信公众号模板消息体为:{}", JSON.toJSON(appWechatInfo));
            String format = DataFormatForWechatApp.create(appWechatInfo).toJSONString();
            LOG.info("请求公众号消息模版发送的参数：{}",format);
            String resParams = OkHttpUtils.postJsonParams(WechatUrlConstants.WECHAT_APP_TEMPLATE_SEND_URL + accessToken,format );
            JSONObject jsonParams = JSONObject.parseObject(resParams);
            LOG.info("获取消息发送返回信息为:{}", jsonParams);
            String errmsg = jsonParams.getString("errmsg");
            LOG.info("错误信息:{}", errmsg);
            String errcode = jsonParams.getString("errcode");
            LOG.info("错误码:{}", errcode);
            if ("40001".equals(errcode)) {
                LOG.info("推送公众号消息AccessToken出错，重新获取AccessToken并执行推送。");
                accessToken = wechatService.redisAccessTokenRedisExpired();
                resParams = OkHttpUtils.postJsonParams(WechatUrlConstants.WECHAT_APP_TEMPLATE_SEND_URL + accessToken, DataFormatForWechatApp.create(appWechatInfo).toJSONString());
                jsonParams = JSONObject.parseObject(resParams);
                LOG.info("重新发送之后的结果:{}", jsonParams);
            }
            if (!errcode.equals("0") || !errmsg.equals("ok")) {
                LOG.error("发送微信公众号模板消息通知失败!失败用户:{}", openId);
            }
        }
        //TODO 后期计数器，统计成功失败条数
        return null;
    }

    /**
     * 微信小程序模板消息
     *
     * @param params
     * @return
     */
    @Override
    public ApiResult doWechatMiniTemplateNotify(Map<String, Object> params) {
        String openId = params.get("openId") == null ? null : params.get("openId").toString();
        String formId = params.get("formId") == null ? null : params.get("formId").toString();
        String templateId = params.get("templateId") == null ? null : params.get("templateId").toString();
        LOG.info("获取前端参数:用户openId:{},模版ID:{},表单ID:{}", openId, templateId, formId);
        String accessToken = wechatService.getProgramAccessToken();
        LOG.info("获取accessToken:{}", accessToken);
        if (StringUtils.isEmpty(openId)) {
            LOG.info("微信小程序用户openID为空");
            return ApiResult.failure("微信小程序用户openID为空");
        }
        if (StringUtils.isEmpty(templateId)) {
            LOG.info("微信小程序模版templateId为空");
            return ApiResult.failure("");
        }
        if (StringUtils.isEmpty(accessToken)) {
            LOG.info("微信小程序accessToken为空");
            return ApiResult.failure("微信小程序模版templateId为空");
        }
        if (StringUtils.isEmpty(formId)) {
            LOG.info("微信小程序formId为空");
            return ApiResult.failure("微信小程序formId为空");
        }
        //获取 keywords包体
        Map<String, String> objParams = JSON.parseObject(params.get("data").toString(), Map.class);
        LOG.info("获取消息体为:{}", objParams);

        if (objParams == null || objParams.size() < 1) {
            LOG.info("消息体数据为空");
            return ApiResult.failure("微信小程序formId为空");
        }
        //获取data消息体Map长度，判断数据量
        List<MiniDataInfo> miniDataInfos = new ArrayList<>();
        for (String key : objParams.keySet()) {
            MiniDataInfo keyword = new MiniDataInfo(key, objParams.get(key));
            miniDataInfos.add(keyword);
        }
        SysconfigPlatformInfoDO sysconfigPlatformInfoDO = ConfigContextHandler.getSysconfigInfo();
        String pagePath = sysconfigPlatformInfoDO.getPagePath();
        //TODO 之前报错的原因是因为你这个list没有声明泛型。
//        List miniData = ListsUtil.newArrayList(miniDataInfos);
        MiniWechatInfo miniWechatInfo = MiniWechatInfo.builder()
                //微信用户ID
                .toUser(openId)
                //模版ID
                .templateId(templateId)
                //微信小程序页面路径
                .page(pagePath)
                //微信表单ID
                .fromId(formId)
                //微信小程序参数信息
                .data(miniDataInfos)
                .build();
        String resParams = OkHttpUtils.postJsonParams(WechatUrlConstants.WECHAT_MINI_TEMPLATE_SEND_URL + accessToken, DataFormatForWeChatMini.create(miniWechatInfo).toJSONString());
        JSONObject jsonParams = JSONObject.parseObject(resParams);
        LOG.info("获取消息发送返回信息为:{}", jsonParams);
        String errmsg = jsonParams.getString("errmsg");
        LOG.info("错误信息:{}", errmsg);
        String errcode = jsonParams.getString("errcode");
        LOG.info("错误码:{}", errcode);
        if (!errcode.equals("0") || !errmsg.equals("ok")) {
            LOG.error("发送微信小程序模板消息通知失败!");
            return ApiResult.failure("发送微信小程序模板消息通知失败!");
        } else {
            LOG.info("微信小程序模板消息通知成功");
            return ApiResult.success("微信小程序模板消息通知成功");
        }
    }

    /**
     * 支付宝生活号
     * 多用户openID群发
     * @param params
     * @return
     */
    @Override
    public ApiResult doAlipayAppTemplateNotify(Map<String, Object> params) {
        LOG.info("支付宝生活号获取参数为:{}",params);
        String toUserIdList=params.get("toUserId")==null?null:params.get("toUserIdList").toString();
        LOG.info("获取toUserId列表为:{}",toUserIdList);
        String[] toUserIdArray=toUserIdList.substring(1,toUserIdList.length()-1).split(",");
        List<String> toUserIds=Arrays.asList(toUserIdArray);
//        String toUserId = params.get("toUserId") == null ? null : params.get("toUserId").toString();
//        Object toUserIdObj = params.get("toUserId") == null ? null : params.get("toUserId");
//        List<String> toUserIdList = (List<String>) toUserIdObj;
        if (toUserIds.size() < 1 || toUserIds == null) {
            LOG.info("生活号用户ID列表数据为空");
            return ApiResult.failure("生活号用户ID列表数据为空");
        }
        String headColor = params.get("headColor") == null ? null : params.get("headColor").toString();
        String actionName = params.get("actionName") == null ? null : params.get("actionName").toString();
        String templateId = params.get("templateId") == null ? null : params.get("templateId").toString();
        LOG.info("获取前端参数:用户ID:{},头部颜色:{},通知名:{},模版ID:{}", toUserIds, headColor, actionName, templateId);
        if (StringUtils.isEmpty(templateId)) {
            LOG.info("支付宝生活号模版templateId为空");
            return ApiResult.failure("支付宝生活号模版templateId为空");
        }
        if (StringUtils.isEmpty(headColor)) {
            LOG.info("支付宝生活号消息头颜色headColor为空");
            return ApiResult.failure("支付宝生活号消息头颜色headColor为空");
        }
        if (StringUtils.isEmpty(actionName)) {
            LOG.info("支付宝生活号消息体名称actionName为空");
            return ApiResult.failure("支付宝生活号消息体名称actionName为空");
        }
        //获取 keywords包体
        Map<String, Object> objParams = JSON.parseObject(params.get("data").toString(), Map.class);
        LOG.info("获取消息体为:{}", objParams);
        if (objParams == null || objParams.size() < 1) {
            LOG.info("消息体数据为空");
            return ApiResult.failure("消息体数据为空");
        }
        //获取data消息体Map长度，判断数据量
        List<AppDataInfo> appDataInfos = new ArrayList<>();
        for (String key : objParams.keySet()) {
            AppDataInfo keyword = new AppDataInfo(key, objParams.get(key).toString(), "#173177");
            appDataInfos.add(keyword);
        }
        SysconfigPlatformInfoDO sysconfigPlatformInfoDO = ConfigContextHandler.getSysconfigInfo();
        String url = sysconfigPlatformInfoDO.getPagePath();
        LOG.info("获取支付宝生活号页面路径为:{}", url);
        if (StringUtils.isEmpty(url)) {
            LOG.info("数据库获取支付宝生活号路径为空");
            return ApiResult.failure("数据库获取支付宝生活号路径为空");
        }
        AppAlipayInfo appAlipayInfo = AppAlipayInfo.builder()
                //支付宝生活号模版ID
                .templateId(templateId)
                .toUserId(null)
                .headColor(headColor)
                .actionName(actionName)
                .url(url)
                .data(appDataInfos)
                .build();
        Iterator<String> toUserIdIterator = toUserIds.iterator();
        AlipayClient alipayClient = new DefaultAlipayClient(sysconfigPlatformInfoDO.getGateUrl(),
                sysconfigPlatformInfoDO.getAppId(),
                sysconfigPlatformInfoDO.getAppSecret(),
                sysconfigPlatformInfoDO.getFormat(),
                sysconfigPlatformInfoDO.getCharset(),
                sysconfigPlatformInfoDO.getPublicKey(),
                sysconfigPlatformInfoDO.getSignType());
        AlipayOpenPublicMessageSingleSendRequest request = new AlipayOpenPublicMessageSingleSendRequest();
        while (toUserIdIterator.hasNext()) {
            String userId = toUserIdIterator.next();
            LOG.info("获取用户ID:{}",userId);
            appAlipayInfo.setToUserId(userId);
            String format=DataFormatForAlipayApp.create(appAlipayInfo).toJSONString();
            LOG.info("支付宝生活号模板消息体为:{}", format);
            //发起支付宝生活号消息通知
            request.setBizContent(format);
            try {
                AlipayOpenPublicMessageSingleSendResponse response = alipayClient.execute(request);
                LOG.info("支付宝生活号消息发送返回体:{}", response);
                if (response.isSuccess()) {
                    LOG.info("发送支付宝生活号模板消息通知成功");
                    return ApiResult.success(ApiResultCode.SUCCESS, "发送支付宝生活号模板消息通知成功");
                } else {
                    LOG.info("发送支付宝生活号模板消息通知失败,失败用户:{}", userId);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 支付宝小程序
     *
     * @param params
     * @return
     */
    @Override
    public ApiResult doAlipayMiniTemplateNotify(Map<String, Object> params) {
        String toUser = params.get("toUser") == null ? null : params.get("toUser").toString();
        String formId = params.get("formId") == null ? null : params.get("formId").toString();
        String templateId = params.get("templateId") == null ? null : params.get("templateId").toString();
        if (StringUtils.isEmpty(toUser)) {
            LOG.info("支付宝小程序用户userId为空");
            return ApiResult.failure("支付宝小程序用户userId为空");
        }
        if (StringUtils.isEmpty(templateId)) {
            LOG.info("支付宝小程序模版templateId为空");
            return ApiResult.failure("支付宝小程序模版templateId为空");
        }
        if (StringUtils.isEmpty(formId)) {
            LOG.info("支付宝小程序表单formId或交易单号tradeNo为空");
            return ApiResult.failure("支付宝小程序表单formId或交易单号tradeNo为空");
        }
        LOG.info("获取前端参数:用户ID:{},表单ID:{},模版ID:{}", toUser, formId, templateId);

        //获取 keywords包体
        Object objectParams = params.get("data");
        LOG.info("获取消息体为:{}", objectParams);
        Map<String, Object> objParams = JSON.parseObject(params.get("data").toString(), Map.class);
        if (objParams == null || objParams.size() < 1) {
            LOG.info("消息体数据为空");
            return ApiResult.failure("消息体数据为空");
        }
        //获取data消息体Map长度，判断数据量
        List<MiniDataInfo> miniDataInfos = new ArrayList<>();
        for (String key : objParams.keySet()) {
            MiniDataInfo keyword = new MiniDataInfo(key, objParams.get(key).toString());
            miniDataInfos.add(keyword);
        }
        SysconfigPlatformInfoDO sysconfigPlatformInfoDO = ConfigContextHandler.getSysconfigInfo();
        String pagePath = sysconfigPlatformInfoDO.getPagePath();
        MiniAlipayInfo miniAlipayInfo = MiniAlipayInfo.builder()
                //支付宝小程序用户ID
                .toUserId(toUser)
                //支付宝模版ID
                .userTemplateId(templateId)
                //支付宝表单ID
                .formId(formId)
                //支付宝页面路径
                .page(pagePath)
                //支付包消息体参数--需要做信息类型区分
                .data(miniDataInfos)
                .build();
        LOG.info("支付宝小程序模板消息体为:{}", miniAlipayInfo);
        //发起支付宝生活号消息通知
        AlipayClient alipayClient = new DefaultAlipayClient(sysconfigPlatformInfoDO.getGateUrl(),
                sysconfigPlatformInfoDO.getAppId(),
                sysconfigPlatformInfoDO.getAppSecret(),
                sysconfigPlatformInfoDO.getFormat(),
                sysconfigPlatformInfoDO.getCharset(),
                sysconfigPlatformInfoDO.getPublicKey(),
                sysconfigPlatformInfoDO.getSignType());
        AlipayOpenPublicMessageSingleSendRequest request = new AlipayOpenPublicMessageSingleSendRequest();
        request.setBizContent(DataFormatForAlipayMini.create(miniAlipayInfo).toJSONString());
        try {
            AlipayOpenPublicMessageSingleSendResponse response = alipayClient.execute(request);
            LOG.info("支付宝小程序消息发送返回体:{}", response);
            if (response.isSuccess()) {
                LOG.info("发送支付宝小程序模板消息通知成功");
                return ApiResult.failure("发送支付宝小程序模板消息通知成功");
            } else {
                LOG.info("发送支付宝小程序模板消息通知失败");
                return ApiResult.failure("发送支付宝小程序模板消息通知失败");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
